package physics;

import java.awt.Color;

import javax.media.j3d.*;
import javax.vecmath.Color3f;
import javax.vecmath.Point3f;
import javax.vecmath.Tuple2f;
import javax.vecmath.Vector2f;

// Isosceles right triangle
public class Polygon extends PhysicsObject {
	public float[] vertices = {0f, 0, (float)Math.random() * .5f + .5f, 0, 1f, 1f, 0, (float)Math.random() * 1.5f + .01f};
	
	public float scale = 1;
	private Vector2f[] vertexCache;
	private Vector2f[] normalCache;
    public Color3f color = new Color3f(1, 1, 1);

    public Polygon() {
        super(1f, 0, 0, 0, 0, 0, 0);
    }

    public void init() {
        calculateCenterOfMass();
        calculateMomentOfInertia();
        this.updateTransformGroup();
        TG.addChild(createShape());
    }
	
	public Polygon(float mass, float positionX, float positionY, float velocityX, float velocityY, float orientation, float angularVelocity, float scale, Color3f color) {
		super(mass, positionX, positionY, velocityX, velocityY, orientation, angularVelocity);

        this.scale = scale;
        this.color = color;

        calculateCenterOfMass();
		calculateMomentOfInertia();

		TG.addChild(createShape());
	}

    public void calculateCenterOfMass() {
        // get center of mass
        float area = 0;
        for (int i = 0; i < vertices.length; i += 2) {
            float x = vertices[i] * scale;
            float y = vertices[i + 1] * scale;
            float x2 = vertices[i + 2 > vertices.length - 1 ? 0 : i + 2] * scale;
            float y2 = vertices[i + 3 > vertices.length - 1 ? 1 : i + 3] * scale;
            centerOfMass.x += ((x + x2) * (x * y2 - x2 * y));
            centerOfMass.y += ((y + y2) * (x * y2 - x2 * y));
            area += (x * y2 - x2 * y);
        }

        area /= 2;
        centerOfMass.x /= (6 * area);
        centerOfMass.y /= (6 * area);
    }

    public void calculateMomentOfInertia() {
        float denom = 0f;
        float numer = 0f;
        for(int i = 0; i < vertices.length; i += 2) {
            Vector2f P0 = new Vector2f(vertices[i] * scale, vertices[i + 1] * scale);
            Vector2f P1 = new Vector2f(vertices[(i + 2)%vertices.length] * scale, vertices[(i + 3)%vertices.length] * scale);
            float a = Math.abs(P0.x * P1.y - P0.y * P1.x);
            float b = P1.dot(P1) + P1.dot(P0) + P0.dot(P0);
            denom += (a * b);
            numer += a;
        }

        momentOfInertia = (mass / 6.0f) * (denom / numer);
    }

	public Polygon(float mass, Tuple2f position, Tuple2f velocity, float orientation, float angularVelocity, float scale, Color3f color) {
		this(mass, position.x, position.y, velocity.x, velocity.y, orientation, angularVelocity, scale, color);
	}
	
	public void clearCaches() {
		vertexCache = null;
		normalCache = null;
	}

	public Vector2f[] getVertices() {
		if (vertexCache == null) {
			vertexCache = new Vector2f[vertices.length / 2];
			for (int i = 0; i < vertices.length; i += 2) {
				float tmpX = vertices[i] * scale;
				float tmpY = vertices[i+1] * scale;
				vertexCache[i/2] = new Vector2f();
				vertexCache[i/2].x = (float)(Math.cos(orientation) * tmpX - Math.sin(orientation) * tmpY) + position.x;
				vertexCache[i/2].y = (float)(Math.sin(orientation) * tmpX + Math.cos(orientation) * tmpY) + position.y;
			}
		}
		return vertexCache;
	}
	
	public Vector2f[] getNormals() {
		if (normalCache == null) {
			Vector2f[] vertices = getVertices();
			normalCache = new Vector2f[vertices.length];

			for (int i = 0; i < vertices.length; i++) {
				normalCache[i] = new Vector2f();
				normalCache[i].scaleAdd(-1, vertices[i], vertices[(i+1)%vertices.length]);
				normalCache[i].normalize();
				float tmp = normalCache[i].x;
				normalCache[i].x = normalCache[i].y;
				normalCache[i].y = -tmp;
			}
		}
		return normalCache;
	}
	
	public Node createShape() {
        TriangleFanArray geometry = new TriangleFanArray(vertices.length, GeometryArray.COORDINATES, new int[] { vertices.length / 2 });
		for (int i = 0; i < vertices.length; i += 2)
			geometry.setCoordinate(i / 2, new Point3f(scale * vertices[i], scale * vertices[i+1], 0));

		PointArray centerOfMassGeometry = new PointArray(1, GeometryArray.COORDINATES);
		centerOfMassGeometry.setCoordinate(0, new Point3f(centerOfMass.x, centerOfMass.y, 0));

		BranchGroup root = new BranchGroup();
		if (color == null)
			color = new Color3f(Color.getHSBColor((float)Math.random(), 1, 1));
		Appearance appearance = new Appearance();
		appearance.setColoringAttributes(new ColoringAttributes(color, ColoringAttributes.FASTEST));
		PolygonAttributes polyAttr = new PolygonAttributes(PolygonAttributes.POLYGON_FILL, PolygonAttributes.CULL_NONE, 0);
		appearance.setPolygonAttributes(polyAttr);
		root.addChild(new Shape3D(geometry, appearance));

		appearance = new Appearance();
		appearance.setPointAttributes(new PointAttributes(4, true));
		root.addChild(new Shape3D(centerOfMassGeometry, appearance));
	
		return root;
	}
}
